package com.ant.collect.service.impl;

import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import com.aliyun.tea.utils.StringUtils;
import com.ant.collect.common.ResultCode;
import com.ant.collect.common.ResultVo;
import com.ant.collect.dto.UserDto;
import com.ant.collect.dto.UserInfoDto;
import com.ant.collect.handler.AntException;
import com.ant.collect.mapper.*;
import com.ant.collect.pojo.*;
import com.ant.collect.pojo.enums.MenuTypeEnum;
import com.ant.collect.service.IUserService;
import com.ant.collect.vo.UserVo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.zip.ZipFile;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author hzd
 * @since 2025-10-23
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    CompanyMapper companysMapper;
    @Autowired
    UserRoleMapper userRoleMapper;
    @Autowired
    RoleMenuMapper roleMenuMapper;
    @Autowired
    MenuMapper menuMapper;

    @Autowired
    RoleMapper roleMapper;


    @Autowired
    CompanyMapper companyMapper;

    @Override
    public Company getUserCompanyId(){
        int userId = StpUtil.getLoginIdAsInt();
        return companyMapper.selectOne(new QueryWrapper<Company>().eq("user_id", userId));
    }

    @Override
    public Map<String, Object> queryUserList(UserDto dto) {
        Page<User> pageInfo = new Page<User>(dto.getPageIndex(), dto.getPageSize());
        String trimUsername = "";
        if(!org.apache.commons.lang.StringUtils.isBlank(dto.getUsername())){
            trimUsername = dto.getUsername().trim();
        }
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq(!org.apache.commons.lang.StringUtils.isBlank(trimUsername),"username",trimUsername);
        Page<User> userPage = baseMapper.selectPage(pageInfo, wrapper);
        if(userPage != null){
            List<User> userList = userPage.getRecords();
            List<UserDto> list = new ArrayList<>();
            if(!CollectionUtils.isEmpty(userList)){
                userList.stream().forEach(user -> {
                    QueryWrapper<UserRole> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("user_id",user.getId());
                    List<Integer> roleIds = userRoleMapper.selectList(queryWrapper).stream().map(UserRole::getRoleId).collect(Collectors.toList());
//                    if(!CollectionUtils.isEmpty(roleIds)){
//                        //用户已经分配过角色
//                        List<String> roles = roleMapper.selectBatchIds(roleIds).stream().map(Role::getRoleName).collect(Collectors.toList());
//                        userList.setRoles(roles);
//                    }
                   // userList.add(userDto);
                });
                Map<String,Object> map = new HashMap<>();
                map.put("data", userList);
                map.put("total", userPage.getTotal());
                return map;
            }
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveRoles(String username, List<String> roles) {
        QueryWrapper<User> userWrapper = new QueryWrapper<>();
        userWrapper.eq("username",username);
        User user = baseMapper.selectOne(userWrapper);
        //分配角色之前，将之前拥有的角色先删除后再重新保存新的角色
        QueryWrapper<UserRole> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",user.getId());
        List<UserRole> userRoles = userRoleMapper.selectList(wrapper);
        if(!CollectionUtils.isEmpty(userRoles)){
            //将原先拥有的角色删除
            List<Integer> roleIds = userRoles.stream().map(UserRole::getRoleId).collect(Collectors.toList());
            QueryWrapper<UserRole> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id",user.getId());
            queryWrapper.in("role_id",roleIds);
            userRoleMapper.delete(queryWrapper);
        }
        //保存新的用户角色
        if(!CollectionUtils.isEmpty(roles)){
            QueryWrapper<Role> queryWrapper = new QueryWrapper<>();
            queryWrapper.in("role_name",roles);
            List<Integer> roleIds = roleMapper.selectList(queryWrapper).stream().map(Role::getId).collect(Collectors.toList());
            roleIds.stream().forEach(roleId -> {
                UserRole userRole = new UserRole();
                userRole.setUserId(user.getId());
                userRole.setRoleId(roleId);
                userRoleMapper.insert(userRole);
            });
        }
    }

    @Override
    public Map<String, Object> getUserInfo(int userId) {
        User user = baseMapper.selectById(userId);
        if (user == null) {
            throw new AntException(ResultCode.USER_NOT_EXITS);
        }
        user.setUserPwd(null);
        //获取当前用户所拥有的所有菜单id
        log.info("用户{}正在菜单和按钮数据.....", user.getUserName());
        //判断当前是否拥有管理员权限
        QueryWrapper<UserRole> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        List<Integer> roleIds = userRoleMapper.selectList(wrapper).stream()
                .map(UserRole::getRoleId).collect(Collectors.toList());
        boolean isAdmin = false;
        if (!CollectionUtils.isEmpty(roleIds)) {
            isAdmin = this.hasAdminPermission(roleIds);
        }
        if ((user.getUserName().equalsIgnoreCase("admin")) || (isAdmin)) {
            //如果用户名是admin则查询所有的菜单和按钮
            return this.queryAdminInfo(user);
        } else {
            //其他角色的用户查询相应的菜单和按钮
            return this.queryOtherInfo(user);
        }
    }

    @Override
    public User getUserByIdInfo(Integer uid) {
        User user = baseMapper.selectById(uid);
        if (user == null) {
            throw new AntException(ResultCode.USER_NOT_EXITS);
        }
         return user;
    }

    @Override
    public Map<String, Object> findResetPassword(int userId) {
        return null;
    }

    @Override
    public List<Menu> getPermission(int userId) {
          //通过用户角色获取菜单
        List<Menu> menuList = getUserPermission(userId);
        return this.getUserMenu(menuList);

    }



    private  List<Menu>  getUserPermission(int userId) {
        QueryWrapper<UserRole> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        //通过用户角色获取菜单menu
        List<Integer> roleIds = userRoleMapper.selectList(wrapper).stream().map(UserRole::getRoleId).collect(Collectors.toList());
        List<RoleMenu> id = roleMenuMapper.selectList(new QueryWrapper<RoleMenu>().in("role_id", roleIds));
        List<Menu> list = menuMapper.selectList(
                new QueryWrapper<Menu>().in("type", MenuTypeEnum.DIRECTORY.getCode(), MenuTypeEnum.MENU.getCode())
                        .in("id", id.stream().map(RoleMenu::getMenuId).collect(Collectors.toList()))
                        .orderByAsc("sort"));
        return list;

    }


    /**
     * 其他角色的用户查询相应的菜单和按钮
     *
     * @param user
     * @return
     */
    private Map<String, Object> queryOtherInfo(User user) {
        //查询相应的目录以及菜单
        //查询用户的角色ids
        QueryWrapper<UserRole> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", user.getId());
        List<Integer> roleIds = userRoleMapper.selectList(wrapper).stream().map(UserRole::getRoleId).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(roleIds)) {
            //说明此用户已经被管理员分配过角色
            //根据角色ids查询相应的所有目录、菜单、按钮，追后过滤出routes和buttons即可
            //存储所有的菜单ids，使用Set存储的目的是去重相同的menuId，因为不同的角色可能会分配到相同的菜单或者按钮权限
            Set<Integer> menuIdSet = new HashSet<>();
            roleIds.stream().forEach(roleId -> {
                QueryWrapper<RoleMenu> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("role_id", roleId);
                List<Integer> menuIds = roleMenuMapper.selectList(queryWrapper).stream().map(RoleMenu::getMenuId).collect(Collectors.toList());
                menuIdSet.addAll(menuIds);
            });

            if (!CollectionUtils.isEmpty(menuIdSet)) {
                List<Menu> menuList = menuMapper.selectBatchIds(menuIdSet);
                //过滤出routes和button
                List<String> routes = menuList.stream()
                        .filter(menu -> (menu.getType() == MenuTypeEnum.DIRECTORY.getCode()) || (menu.getType() == MenuTypeEnum.MENU.getCode()))
                        .collect(Collectors.toList())
                        .stream().map(Menu::getName).collect(Collectors.toList());
                List<String> buttons = menuList.stream()
                        .filter(menu -> menu.getType() == MenuTypeEnum.BUTTON.getCode())
                        .collect(Collectors.toList())
                        .stream().map(Menu::getButton).collect(Collectors.toList());

                List<Menu> userMenu = getUserMenu(menuList);
                List<String> roles =roleMapper.selectRolesList(user.getId());
                Map<String, Object> map = new HashMap<>();
                map.put("routes", routes);
                map.put("user", user);
                map.put("button", buttons);
                map.put("roles",roles);
                map.put("menus",userMenu);

                StpUtil.getSession().set("permissions", buttons);
                StpUtil.getSession().set("roleList", roles);
                return map;
            }
        }
        return null;
    }
    private boolean hasAdminPermission(List<Integer> roleIds) {
        boolean isAdmin = false;
        List<Role> roleList = roleMapper.selectBatchIds(roleIds);
        for (int i = 0; i < roleList.size(); i++) {
            if(roleList.get(i).getRoleName().equalsIgnoreCase("管理员")){
                isAdmin = true;
                break;
            }
        }
        return isAdmin;
    }

    /**
     * (管理员)查询所有的菜单和按钮
     * 查询所有的目录以及菜单
     * @param user
     * @return
     */
    private Map<String,Object> queryAdminInfo(User user) {

        QueryWrapper<Menu> wrapper = new QueryWrapper<>();
        wrapper.eq("type", MenuTypeEnum.DIRECTORY.getCode())
                .or().eq("type", MenuTypeEnum.MENU.getCode());
        List<String> routes = menuMapper.selectList(wrapper).stream().map(Menu::getName).collect(Collectors.toList());
        //获取所有的按钮
        QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("type", MenuTypeEnum.BUTTON.getCode());
        List<String> buttons = menuMapper.selectList(queryWrapper).stream().map(Menu::getButton).collect(Collectors.toList());
        List<String> roles =roleMapper.selectRolesList(user.getId());
        List<Menu> menus = menuMapper.selectList(null);
        List<Menu> userMenu = getUserMenu(menus);
        Map<String,Object> map = new HashMap<>();
        map.put("routes", routes);
        map.put("user", user);
        map.put("button", buttons);
        map.put("roles",roles);
        map.put("menu",userMenu);
        // 将权限绑定到当前登录用户（会自动存入 Sa-Token 的会话中）
        StpUtil.getSession().set("permissions", buttons);
        StpUtil.getSession().set("roleList", roles);
        return map;
    }


    /**
     * 获取当前登录用户的权限菜单（树形结构）
     */
    public List<Menu> getUserMenu(List<Menu> menuList) {
        // 1. 获取当前用户拥有的权限（结合Sa-Token）
       // List<String> userPermissions = StpUtil.getPermissionList(); // Sa-Token获取当前用户权限

        // 2. 根据权限查询菜单（如果是超级管理员，可直接查询所有菜单）
//        List<Menu> allMenus;
//        if (StpUtil.hasRole("admin")) { // 假设admin角色拥有所有权限
//            allMenus = menuMapper.selectList(null);
//        } else {
//            allMenus = menuMapper.selectByPermissions(userPermissions);
//        }

        // 3. 构建树形结构（顶级菜单parentId=0）
        return buildTree(menuList, 0);
    }

    /**
     * 递归构建菜单树形结构
     * @param allMenus 所有菜单列表
     * @param parentId 父菜单ID
     */
    private List<Menu> buildTree(List<Menu> allMenus, Integer parentId) {
        // 筛选出父菜单ID为parentId的菜单
        return allMenus.stream()
                .filter(menu -> menu.getParentId().equals(parentId))
                .map(menu -> {
                    // 递归设置子菜单
                    menu.setChildren(buildTree(allMenus, menu.getId()));
                    return menu;
                })
                .collect(Collectors.toList());
    }

    @Override
    public ResultVo queryUserOne(String id) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", id);
        User user = this.getOne(queryWrapper);
        return ResultVo.success("ok", user);
    }

    @Override
    @Transactional
    public Object saveUser(UserDto dto) {

        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("user_name", dto.getContactTel());
        User one = baseMapper.selectOne(wrapper);
        if (one != null) {
            throw new AntException(ResultCode.FAILURE.getResultCode(), "该用户已存在");
        }

        User user = new User();
        user.setUserName(dto.getContactTel());
        user.setUserPwd(dto.getUserPwd());
        user.setReview(1);
        user.setCreationTime(LocalDateTime.now());
        user.setAccountType(dto.getAccountType() == null ? 1 : dto.getAccountType());
        baseMapper.insert(user);

        Company companys = new Company();
        companys.setUserId(user.getId());
        companys.setProvince(dto.getProvince());
        companys.setCity(dto.getCity());
        companys.setCounty(dto.getCounty());
        companys.setAddress(dto.getAddress());
        companys.setCompanyCode(dto.getCompanyCode());
        companys.setCompanyName(dto.getCompanyName());
        companys.setBusinessUrl(dto.getBusinessUrl());
        companys.setPersonName(dto.getPersonName());
        companys.setPersonUrl(dto.getPersonUrl());
        companys.setContact(dto.getContact());
        companys.setContactTel(dto.getContactTel());
        companys.setCreationTime(new Date());
        companysMapper.insert(companys);
        return user;
    }

    @Override
    public User updateUserById(UserDto dto) {
        if (dto.getId() == null) {
            throw new AntException("输入id");
        }
        User user = new User();
        user.setUserName(dto.getContactTel());
        user.setUserPwd(dto.getUserPwd());
        user.setReview(1);
        user.setCreationTime(LocalDateTime.now());
        user.setAccountType(dto.getAccountType() == null ? 1 : dto.getAccountType());
        user.setId(dto.getId());
        baseMapper.updateById(user);
        Company companys = new Company();
        companys.setUserId(user.getId());
        companys.setProvince(dto.getProvince());
        companys.setCity(dto.getCity());
        companys.setCounty(dto.getCounty());
        companys.setAddress(dto.getAddress());
        companys.setCompanyCode(dto.getCompanyCode());
        companys.setCompanyName(dto.getCompanyName());
        companys.setBusinessUrl(dto.getBusinessUrl());
        companys.setPersonName(dto.getPersonName());
        companys.setPersonUrl(dto.getPersonUrl());
        companys.setContact(dto.getContact());
        companys.setContactTel(dto.getContactTel());
        companys.setCreationTime(new Date());
        companysMapper.insert(companys);
        return user;
    }

    @Override
    public Map<String,String> selectUserPwd(UserInfoDto dto) throws AntException{
        Map<String,String> map=new HashMap<>();
        // 1. 查询用户信息（从数据库获取加密后的密码）
        if (StringUtils.isEmpty(dto.getUsername().trim()) || StringUtils.isEmpty(dto.getPassword().trim())) {
            log.error("用户[{}]登录失败：密码错误", dto.getUsername());
            throw new AntException(201, "请输入账号或密码");
        }
//        if(StringUtils.isEmpty(dto.getUsername().trim()) || StringUtils.isEmpty(dto.getPassword().trim()) ){
//            throw new AntException(201,"请输入账号或密码");
//        }



        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_name", dto.getUsername());
        User user = this.getOne(queryWrapper);
        boolean empty = ObjectUtils.isEmpty(user);
        if (empty) {
            log.error("用户[{}]登录失败：密码错误", dto.getUsername());
            throw new AntException(201, "用户名或密码错误");
        }
        //
        if(user.getAccountType()==2){
            Company company = companysMapper.selectOne(new QueryWrapper<Company>()
                    .eq("user_id", user.getId()));
            if(company.getReview()!=2 ){
                throw new AntException(201, "账号审核中");
            }
        }

        // 2. 验证密码（使用 BCrypt 校验输入密码与数据库存储的哈希值）
        boolean passwordMatch = BCrypt.checkpw(dto.getPassword(), user.getUserPwd());
        if (!passwordMatch) {
            log.error("用户[{}]登录失败：密码错误", dto.getUsername());
            throw new AntException(201, "密码错误");
        }
        // 原始密码
        // 1. 生成加密后的密码（BCrypt 自动生成盐值，无需手动管理）
        // String encryptedPassword = BCrypt.hashpw(password, BCrypt.gensalt(12)); // 工作因子12

        // 3. 存储到数据库（仅存储加密后的密码，不存储明文）
        StpUtil.login(user.getId());
        // 第四步:根据用户角色不的不同,赋予不同的权限
        List<String> permissionListResult = setUsernamePermission(user.getAccountType());
        // 把该用户的权限存储到 Sa-Token的session中
        StpUtil.getSession().set("permissionList", permissionListResult);

        // 获取token 参数
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        SaResult result = SaResult.data(tokenInfo);
        String token = StpUtil.getTokenValueByLoginId(user.getId());
        map.put("token",token);
        return map;
    }



    @Override
    public List<UserVo> userlist() {
        return baseMapper.userlist();
    }

    @Override
    public void reviewUser(Integer id) {
        User user1 = baseMapper.selectById(id);
        if (user1 == null) {
            throw new AntException(201, "用户不存在!");
        }
        User user = new User();
        user.setReview(1);
        user.setReviewTime(LocalDateTime.now());
        user.setReviewName("admin");// 登录账号信息
        user.setIsOpen(0);
        user.setId(id);
        baseMapper.updateById(user);
    }

    @Override
    public String saveUserMsg(String username, String password) {
        String encryptedPassword = BCrypt.hashpw(password.trim(), BCrypt.gensalt(12)); // 工作因子12
        System.out.println("encryptedPassword--" + encryptedPassword);
        User user = new User();
        user.setUserName(username.trim());
        user.setUserPwd(encryptedPassword);
        user.setReview(1);
        user.setCreationTime(LocalDateTime.now());
        user.setReviewTime(LocalDateTime.now());
        user.setAccountType(1);
        baseMapper.insert(user);
        return null;
    }

    /**
     * 根据用户类型的不同授予不同的权限
     * 1:管理员 2:访客
     */
    public List<String> setUsernamePermission(Integer userType) {
        ArrayList<String> permissionList = new ArrayList<>();
        switch (userType) {
            case 1:
                // 1:代表管理员权限,拥有所有权限
                permissionList.add("*");
                return permissionList;
            case 2:
                // 2:代表访客权限,可以查看用户信息,不能增删改用户信息
                Collections.addAll(permissionList, "/select");
                return permissionList;
            default:
                return null;
        }
    }

    public static void main(String[] args) {
//        String encryptedPassword = BCrypt.hashpw("123456", BCrypt.gensalt(12)); // 工作因子12
//        System.out.println(encryptedPassword);

        String zipFilePath = "E:/924/11月批次保单.zip"; // 压缩包路径
        zipUploades2(zipFilePath);

    }

    @Override
    public void zipUploades(MultipartFile file) {
        String zipFilePath = file.getName();
        try (ZipFile zipFile = new ZipFile(zipFilePath)) { // 自动关闭ZipFile
            // 遍历压缩包中的所有条目
            zipFile.stream().forEach(entry -> {
                try {
                    // 筛选出PDF文件（通过文件名后缀判断）
                    if (!entry.isDirectory() && entry.getName().toLowerCase().endsWith(".pdf")) {
                        System.out.println("解析PDF文件：" + entry.getName());
                        // 获取PDF文件的输入流
                        try (InputStream inputStream = zipFile.getInputStream(entry)) {
                            // 解析PDF内容
                            parsePdfContent(inputStream);
                        }
                    }
                } catch (Exception e) {
                    System.err.println("处理条目 " + entry.getName() + " 失败：" + e.getMessage());
                }
            });
        } catch (IOException e) {
            System.err.println("读取压缩包失败：" + e.getMessage());
        }
    }

    public static void zipUploades2(String zipFilePath) {
        try (ZipFile zipFile = new ZipFile(zipFilePath, Charset.forName("GBK"))) { // 自动关闭ZipFile
            // 遍历压缩包中的所有条目
            zipFile.stream().forEach(entry -> {
                try {
                    // 筛选出PDF文件（通过文件名后缀判断）
                    if (!entry.isDirectory() && entry.getName().toLowerCase().endsWith(".pdf")) {
                        System.out.println("解析PDF文件：" + entry.getName());
                        // 获取PDF文件的输入流
                        try (InputStream inputStream = zipFile.getInputStream(entry)) {
                            // 解析PDF内容
                            parsePdfContent(inputStream);
                        }
                    }
                } catch (Exception e) {
                    System.err.println("处理条目 " + entry.getName() + " 失败：" + e.getMessage());
                }
            });
        } catch (IOException e) {
            System.err.println("读取压缩包失败：" + e.getMessage());
        }
    }


    /**
     * 解析PDF输入流的内容（提取文本为例）
     * @param pdfInputStream PDF文件的输入流
     */
    private static String  parsePdfContent(InputStream pdfInputStream) {

        String keyword = "保险费合计 ( 人民币大写 )";
        // 正则匹配：关键词后跟随的大写金额（匹配中文大写数字及单位）
        // 大写金额格式：零、壹、贰...佰、仟、万、亿、元、角、分等
        String regex = keyword + "\\s*[:：]?\\s*([零壹贰叁肆伍陆柒捌玖拾佰仟万亿圆角分]+)";

        try (PDDocument document = PDDocument.load(pdfInputStream)) { // 加载PDF文档
            if (document.isEncrypted()) {
                System.out.println("PDF文件已加密，无法解析");
                return null;
            }
            // 提取PDF文本
            PDFTextStripper stripper = new PDFTextStripper();
            String text = stripper.getText(document);
            // 去除文本中的换行符，避免关键词被拆分
            text = text.replaceAll("\\r|\\n", " ");

            // 正则匹配关键词后的大写金额
            Pattern pattern = Pattern.compile(regex);
            Matcher matcher = pattern.matcher(text);

            if (matcher.find()) {
                System.out.println("匹配到的金额：" + matcher.group(1));
                return matcher.group(1).trim(); // 返回匹配到的大写金额
            } else {
                System.out.println("未找到目标金额");
                return null;
            }
            // 如需其他操作（如提取图片、元数据等，可参考PDFBox API）
        } catch (IOException e) {
            e.printStackTrace();
            System.err.println("解析PDF失败：" + e.getMessage());
        }
        return null;
    }
}
